package download;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.concurrent.atomic.AtomicBoolean;

class DownloadTask implements Runnable {

    private final String url;
    private final Downloader downloader;
    private final DownloadFile downloadFile;
    private final int threadId;

    private final AtomicBoolean canceled;

    // 下载的文件区
    private long lowerBound;
    private long upperBound;

    DownloadTask(String url, Downloader downloader, DownloadFile downloadFile, int threadId) {
        this.url = url;
        this.downloader = downloader;
        this.downloadFile = downloadFile;
        this.threadId = threadId;
        this.canceled = new AtomicBoolean(false);
    }

    @Override
    public void run() {
        InputStream input = null;
        try {
            byte[] buffer = new byte[1024 * 1024 * 2];
            input = connect();
            System.out.println("* [线程" + threadId + "]连接成功，开始下载...");

            int len;
            while (!canceled.get() && lowerBound <= upperBound) {
                len = input.read(buffer);
                if (len > 0) {
                    downloadFile.write(buffer, len, lowerBound, threadId, upperBound);
                    lowerBound += len;
                }
            }
            if (!canceled.get()) {
                System.out.println("* [线程" + threadId + "]下载完成" + ": " + lowerBound + "-" + upperBound);
            }
        } catch (IOException e) {
            downloader.cancel();
            System.err.println("x [线程" + threadId + "]遇到错误[" + e.getMessage() + "]，结束下载");
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
    }

    /**
     * 连接WEB服务器，并返回一个数据通道
     * @return 返回通道
     * @throws IOException 网络连接错误
     */
    private InputStream connect() throws IOException {
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setConnectTimeout(3000);
        conn.setReadTimeout(60000);
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Range", "bytes=" + lowerBound + "-" + upperBound);
        conn.connect();

        int statusCode = conn.getResponseCode();
        if (HttpURLConnection.HTTP_PARTIAL != statusCode) {
            conn.disconnect();
            throw new IOException("状态码错误：" + statusCode);
        }
        return conn.getInputStream();
    }

    public void setIdx(long lowerBound, long upperBound) {
        this.lowerBound = lowerBound;
        this.upperBound = upperBound;
    }

    public void cancel() {
        this.canceled.set(true);
    }
}
